package com.divillysausages.dsair.input 
{
	import com.divillysausages.dsair.DSAir;
	import flash.events.KeyboardEvent;
	import flash.utils.Dictionary;
	
	/**
	 * The input manager to easily control key bindings
	 * @author Damian Connolly
	 */
	public class InputManager 
	{
		
		/********************************************************************/
		
		private static var m_instance:InputManager 	= null;	// the singleton instance of this class
		private static var m_creating:Boolean		= false;// are we creating this class?
		
		/********************************************************************/
		
		/**
		 * Gets the singleton instance of the InputManager
		 */
		public static function get instance():InputManager
		{
			if ( InputManager.m_instance == null )
			{
				InputManager.m_creating = true;
				InputManager.m_instance	= new InputManager;
				InputManager.m_creating = false;
			}
			return InputManager.m_instance;
		}
		
		/********************************************************************/
		
		private var m_bindings:Dictionary = new Dictionary( true ); // the bindings that we have for the keys
		
		/********************************************************************/
		
		/**
		 * Creates the InputManager. As InputManager is a singleton, this shouldn't be
		 * called directly. Go through the static instance getter instead
		 */
		public function InputManager() 
		{
			if ( !InputManager.m_creating )
				throw new Error( "The InputManager is a singleon. Use the static instance getter instead" );
		}
		
		/**
		 * Binds a key to get called when it's pressed
		 * @param key The key to bind
		 * @param callback The callback to call when it's pressed. It should take one parameter of type KeyboardEvent
		 */
		public function bind( key:uint, callback:Function ):void
		{
			// check the callback
			if ( callback.length > 1 )
				return DSAir.error( this, "The bind callback either takes no parameters, or one parameter of type KeyboardEvent" );
			
			// check we don't already have a binding
			if ( key in this.m_bindings )
				return DSAir.error( this, "Can't bind the key " + key + " as we already have a binding for it" );
			
			// add the binding
			this.m_bindings[key] = callback;
			
			// activate
			this._activate();
		}
		
		/**
		 * Unbind a previously bound key
		 * @param key The key to unbind
		 */
		public function unbind( key:uint ):void
		{
			// check that it's actually there
			if ( !( key in this.m_bindings ) )
				return;
				
			// remove the binding
			this.m_bindings[key] = null;
			delete this.m_bindings[key];
			
			// deactivate if needed
			this._deactivate();
		}
		
		/********************************************************************/
		
		// activates the input manager
		private function _activate():void
		{
			// just add an event listener - it'll get overwritten if it's already there
			DSAir.stage.addEventListener( KeyboardEvent.KEY_DOWN, this._onKeyDown );
		}
		
		// deactivates the input manager
		private function _deactivate():void
		{
			// if we still have a binding, do nothing
			var count:int = 0;
			for ( var key:* in this.m_bindings )
			{
				count++;
				break; // we only need one
			}
			
			// no more bindings, remove the event listener
			if ( count == 0 )
				DSAir.stage.removeEventListener( KeyboardEvent.KEY_DOWN, this._onKeyDown );
		}
		
		// calle when a key is pressed and we're active
		private function _onKeyDown( e:KeyboardEvent ):void
		{
			// check do we have a binding for this
			if ( e.keyCode in this.m_bindings )
			{
				// if there's no parameters on the callback, just call it, otherwise pass the event
				var callback:Function = this.m_bindings[e.keyCode];
				if ( callback.length == 0 )
					callback();
				else
					callback( e );
			}
		}
		
	}

}